package com.justech.mes.utils.excel;

import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.ss.usermodel.*;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
 * @author feifei.li
 */
public class ImportToBean {

    /**
     * 导入数据时，大多以List的结构呈现给使用者
     *
     * @param workbook
     * @param t
     * @param <T>
     * @return
     */
    public static <T> List<T> getBeanFormWorkbook(Workbook workbook, Class<T> t, Callback<T> callback) throws Exception {
        Sheet sheet = workbook.getSheetAt(0);
        int rowNum = sheet.getLastRowNum();
        //获取T中需要导如的属性
        List<ExcelUtil.Entry<String, Field>> metaData = getMetaData(t);
        ArrayList<T> beans = new ArrayList<>();
        for (int i = 1; i <= rowNum; i++) {
            Row row = sheet.getRow(i);
            if (metaData != null && metaData.size() > 0) {
                T instance = getInstance(t);
                for (int j = 0; j < metaData.size(); j++) {
                    ExcelUtil.Entry<String, Field> entry = metaData.get(j);
                    Cell cell = row.getCell(j);
                    /*当前属性对象*/
                    Field beanField = entry.getValue();
                    try {
                        Object value = getCellValue(cell, beanField);
                        beanField.set(instance, value);
                    } catch (Exception e) {
                        throw new Exception("在第" + i + "行的" + beanField.getName() + "出现了数据异常，请排查");
                    }
                }
                if (callback != null) {
                    callback.execute(instance);
                }
                beans.add(instance);
            }
        }
        return beans;
    }

    public static <T> T getInstance(Class<T> t) {
        try {
            return t.newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    private static String INTEGER = "java.lang.Integer";
    private static String INT = "int";

    private static String DOUBLEOBJECT = "java.lang.Double";
    private static String DOUBLE = "double";

    private static Object getCellValue(Cell cell, Field field) {

        String type = field.getType().getTypeName();
        if (INTEGER.equals(type) || INT.equals(type)) {
            cell.setCellType(CellType.STRING);
            return Integer.valueOf(cell.getStringCellValue());
        } else if (DOUBLEOBJECT.equals(type) || DOUBLE.equals(type)) {
            return cell.getNumericCellValue();
        } else {
            return cell.getStringCellValue();
        }
    }

    private static List<ExcelUtil.Entry<String, Field>> getMetaData(Class t) {
        Field[] fields = t.getDeclaredFields();
        List<ExcelUtil.Entry<String, Field>> entrys = new ArrayList<>();
        for (Field f : fields) {
            f.setAccessible(true);
            Title title = f.getAnnotation(Title.class);
            if (title != null) {
                String type = title.type();
                if (type != null && Title.IMPORT.equals(type)) {
                    entrys.add(new ExcelUtil.Entry(title.name(), f));
                }
            }
        }
        return entrys;
    }

    public static <T> List<T> invokeImport(InputStream inputStream, Class<T> t) {
        return invokeImport(inputStream, t, null);
    }

    public static <T> List<T> invokeImport(InputStream inputStream, Class<T> t, Callback<T> callback) {
        try {
            List<T> ts = getBeanFormWorkbook(WorkbookFactory.create(inputStream), t, callback);
            return ts;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InvalidFormatException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
}
